home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / unix / sgmlc / sgmlio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-03  |  16.3 KB  |  317 lines

  1. /******************************************************************************/
  2. /* Struct iofcb definition moved to ENVCB.H for use by SGMLMSG.C also.        */
  3. /* SAVESTR() and VMALLOC() moved to SGMLMEM.C (memory functions, not I/O).    */
  4. /* SGMLMSG.C now called directly by parser (not default call to SGMLIO).      */
  5. /* FILENAME changed to FILENM here, in SGMLCB.H, and wherever else used.      */
  6. /******************************************************************************/
  7. #include "vmincl.h"           /* Include files for VM. */
  8. #include "vmxtrn.h"           /* Declarations for VM public variables. */
  9. /******************************************************************************/
  10. #define OKIO(rc) ((rc)>0)     /* OPEN return: 1=good; 0=error. */
  11. #define OPENREAD (int)(O_RDONLY|O_BINARY) /* Low-level I/O: binary read. */
  12. /******************************************************************************/
  13. /* Functions used in this module only.
  14. */
  15. struct iofcb *fcbgen(char *);
  16. void fcbnext(struct iofcb *);
  17. void readeof(struct iofcb *, char *, int *);
  18. int readcat(struct iofcb *);
  19. int readfrst(struct iofcb *, char *);
  20. /******************************************************************************/
  21. /* SGMLIO: Text processor I/O services for SGML.
  22.    SGML must see a file in which RE and RS (CR/LF) are present between records,
  23.    and EOFCHAR (Ctl-Z) is present at the end.  SGMLIO must supply these
  24.    characters if they are not naturally present in the file.
  25.    SGML will open two files at a time: when an entity is nested, the
  26.    new file is opened before closing the old in order to make sure the
  27.    open is successful. If it is, the original open file is closed temporarily
  28.    (FILEPEND); when the stack is popped, the new file is closed and the original
  29.    file is re-opened (FILECONT). SGML will check error returns
  30.    for the initial open of a file and all reads, and for re-openings when the
  31.    stack is popped, but not for closes.  Setting io.ipbrc<0 indicates
  32.    an error; 0 or more is a successful operation,
  33.    except for READ where io.ipbrc is the number of characters read, and must
  34.    exceed 0 to be successful.  The first READ must always be successful, and
  35.    normally consists of just priming the buffer with EOBCHAR (or RS EOBCHAR).
  36.    SGMLIO must assure that there is an EOBCHAR at the end of each block read,
  37.    except for the last block of the entity, which must have an EOFCHAR.
  38.  
  39.    SGML views an entity as a contiguous whole, without regard to its
  40.    actual form of storage.  SGMLIO supports entities that are equivalent
  41.    to a single file of one or more records, or to a concatenation of
  42.    files (e.g., "profile.gml;main.gml").  It also recognizes
  43.    an initial code that indicates whether prefixing of an RS and/or trimming
  44.    of a trailing RE/RS are wanted (e.g., "3=profile.gml;main.gml").
  45.    If the code is 1 or 3 (the default), RS is prefixed to the first
  46.    record read for a file.  If 2 or 3 (the default), an RE/RS sequence
  47.    occurring at the end of a file (before the EOF) will be trimmed.  Many
  48.    editors insert such a sequence to allow file concatenation, but it can
  49.    cause an extraneous space to occur when formatting.
  50.    A default setting is contained in boundsw, which can be gotten from the
  51.    command line or a processing instruction.  A code of 4 in a system identifier
  52.    means to use the default value for that file, just as if no code were
  53.    specified.  A code of 0 means that no special treatment is wanted.
  54. */
  55. VOID sgmlio(io)
  56. struct ipbfile *io;           /* IPB: file I/O services. */
  57. {
  58.      struct iofcb *f;         /* Active file control block. */
  59.      int fnum;                /* READ: Return code from DOS. */
  60.      char *flast;             /* READ: Last char read into buffer. */
  61.  
  62.      switch (io->ipbtype) {
  63.      case FILENM:             /* Generate fileid from name & external ID. */
  64.           io->ipbn = (UNIV)savestr(xidgen((struct fpi *)io->ipbn));
  65.           return;
  66.      case FILEOPEN:           /* Open new file for binary read-only. */
  67.           f = fcbgen((UNCH *)io->ipbn);             /* Generate FCB. */
  68.           io->ipbn = (UNIV)f;                       /* Return its pointer. */
  69.           fcbnext(f);                               /* Make it next file. */
  70.           f->fcbfd =  open(f->fcbfile+1, OPENREAD); /* Open file. */
  71.           io->ipbrc = OKIO(f->fcbfd) ? 1 : -1;      /* Normalize return code. */
  72.           f->fcbfirst = 1;                          /* Next read is first. */
  73.           return;
  74.      case FILEREAD:           /* Read file at current location. */
  75.           f = (struct iofcb *)io->ipbn;      /* Get FCB pointer. */
  76.           if (f->fcbfirst) {                 /* Fake first READ of an entity. */
  77.                fnum = readfrst(f, io->ipbbuf);
  78.                goto readrtrn;
  79.           }
  80.           if (f->fcbcatsw && readcat(f)) {   /* Open catenated file, if due. */
  81.                fnum = -1; goto readrtrn;     /* Return if can't open it. */
  82.           }
  83.           f->fcboff = tell(f->fcbfd);        /* Location of START of block.*/
  84.           if (eof(f->fcbfd)) {               /* File ended on previous READ. */
  85.                *io->ipbbuf = EOFCHAR;        /* Fake read of Ctl-Z. */
  86.                fnum = 1;
  87.           }
  88.           else fnum =  read(f->fcbfd, io->ipbbuf, readcnt); /* Read the file. */
  89.           if (fnum<0) goto readrtrn;         /* Return if read error. */
  90.           flast = io->ipbbuf + fnum-1;       /* Last character read. */
  91.           if (*flast==EOFCHAR || fnum<readcnt) readeof(f, flast, &fnum);
  92.           else *(io->ipbbuf + fnum++) = EOBCHAR;  /* Add EOB char. */
  93.           readrtrn:
  94.           io->ipbrc = fnum;                                /* Do return code.*/
  95.           return;
  96.      case FILEPEND:           /* Close file temporarily. */
  97.           (f = IPBFCB)->fcbcatsw = 0;                   /*Resume in same file.*/
  98.           lseek(f->fcbfd, f->fcboff, SEEK_SET);         /* Start of block. */
  99.           lseek(f->fcbfd, (long)io->ipboff, SEEK_CUR);  /* Current char. */
  100.           f->fcboff =  tell(f->fcbfd);                  /* Save location. */
  101.            close(f->fcbfd);
  102.           return;
  103.      case FILECONT:           /* Reopen file; position to saved location. */
  104.           f->fcbfd =  open((f = IPBFCB)->fcbfile+1, OPENREAD);
  105.           io->ipbrc = OKIO(f->fcbfd) ? 1 : -1;
  106.           if (io->ipbrc>0)
  107.               io->ipbrc = (int)lseek(f->fcbfd, f->fcboff, SEEK_SET);
  108.           return;
  109.      case FILECLOS:           /* Close file permanently. */
  110.            close(IPBFCB->fcbfd);
  111.           free((UNIV)IPBFCB);
  112.           return;
  113.      }
  114. }
  115. /******************************************************************************/
  116. /* READEOF: Process end of file.  There are three possibilities:
  117.             1. Data and Ctl-Z read.
  118.             2. Data only read.
  119.             3. Ctl-Z only read.
  120. */
  121. void readeof(f, flast, pfnum)
  122. struct iofcb *f;              /* Pointer to file control block. */
  123. char *flast;                  /* Last char read into buffer. */
  124. int *pfnum;                   /* Number of chars read. */
  125. {
  126.      int eofsw = 0;           /* 1=EOFCHAR present; 0=supply one. */
  127.  
  128.      if (*flast==EOFCHAR) eofsw = 1;    /* Set switch if EOF present. */
  129.      else {++flast; ++*pfnum;}          /* Prepare for EOF or EOB. */
  130.      if (f->fcbnext) {                  /* Another file in this entity? */
  131.           f->fcbcatsw = 1;              /* For next READ. */
  132.           *flast = EOBCHAR;             /* Not entity end. */
  133.      }
  134.      else {                             /* Entity ended: */
  135.           if (!eofsw)                   /* If no EOF char? */
  136.                *flast = EOFCHAR;        /* Add EOF char. */
  137.           else if ( f->fcbRE            /* EOF was there: is RE trim wanted? */
  138.             && *pfnum>=3                /* At least 2 chars before EOF? */
  139.             && *(--flast)==0x0A         /* Is RS there? */
  140.             && *(--flast)==0x0D )       /* Is RE there? */
  141.                {*flast = EOFCHAR; *pfnum -= 2;}    /* Cut them off. */
  142.      }
  143. }
  144. /******************************************************************************/
  145. /* READCAT: Open concatenated file in current entity.
  146.             Returns 1 if open was successful, 0 if not.
  147. */
  148. int readcat(f)
  149. struct iofcb *f;              /* Pointer to file control block. */
  150. {
  151.      f->fcbcatsw = 0;         /* Next read will not be new concatenated file. */
  152.       close(f->fcbfd);        /* Close old file.*/
  153.      fcbnext(f);              /* Find new file. */
  154.      f->fcbfd =  open(f->fcbfile+1, OPENREAD);
  155.      return (!OKIO(f->fcbfd));
  156. }
  157. /******************************************************************************/
  158. /* READFRST: Simulate first READ of entity in order to handle RS insertion
  159.              and guarantee an error-free return.
  160. */
  161. int readfrst(f, ipbbuf)
  162. struct iofcb *f;              /* Pointer to file control block. */
  163. char *ipbbuf;                 /* IPBFILE: Ptr to SGML read buffer. */
  164. {
  165.      f->fcbfirst = 0;                   /* Next read will no longer be first. */
  166.      if (f->fcbRS) {                    /* RS prefix wanted? */
  167.         *((STRING)ipbbuf) = RSCHAR;     /* Put RS in buffer. */
  168.         *((STRING)ipbbuf+1) = EOBCHAR;  /* And end block. */
  169.         return(2);                      /* Successful "read" */
  170.      }
  171.      /* else */
  172.         *((STRING)ipbbuf) = EOBCHAR;    /* Put EOB in buffer. */
  173.         return(1);                      /* Successful "read" */
  174. }
  175. /******************************************************************************/
  176. /* FCBGEN: Generates a file control block from an external identifier.
  177. */
  178. struct iofcb *fcbgen(x)
  179. UNCH *x;                      /* Ptr to external ID (len+EOS). */
  180. {
  181.      struct iofcb *f;         /* Ptr to new fcb. */
  182.  
  183.      f = (struct iofcb *)vmalloc((UNS)sizeof(struct iofcb));
  184.      f->fcbxid = x;
  185.      f->fcbRS = (int)*(x+1)-'0' & 1;
  186.      f->fcbRE = (int)*(x+1)-'0' & 2;
  187.      f->fcbnext = x+3;
  188.      return(f);
  189. }
  190. /******************************************************************************/
  191. /* FCBNEXT: Generates next full system fileid for a file control block.
  192. */
  193. VOID fcbnext(f)
  194. struct iofcb *f;              /* Pointer to file control block. */
  195. {
  196.      UNS i;                   /* Work variable. */
  197.      UNCH *p, *n;             /* Work variable. */
  198.  
  199.      if ((p = f->fcbnext)==0) return;   /* Return if no more files for entity.*/
  200.      f->fcbnext = 0;                    /* Assume this file is the last. */
  201.      if ((n = strchr(p, ';'))!=0) {     /* If ; found, there is still another.*/
  202.           *n = EOS;                     /* Temporary EOS for strlen to use. */
  203.           f->fcbnext = n+1;             /* Location of next file after this. */
  204.      }
  205.      i = strlen(p);                     /* Get length of this file name. */
  206.      memcpy(pd+1, p, ++i);              /* Move to buffer to work on it. */
  207.      *pd = (char)++i;                   /* Prefix length to it. */
  208.      p = xidpath(pd);                   /* Complete the fileid (if necessary).*/
  209.      memcpy(f->fcbfile, p, *p);         /* Save full fileid in fcb. */
  210.      if (f->fcbnext) *n = ';';          /* Put the ; back in the xid. */
  211. }
  212. /******************************************************************************/
  213. /* XIDGEN: Generates a system identifier (fileid) from a name,
  214.            and possibly a public or system identifier as well.
  215.            It returns a ptr to the fileid in the fpi or in the pd buffer.
  216.            Note 1: This routine assumes that an installation assigns
  217.            reserved entity names that correspond to public identifiers, so it
  218.            ignores the actual public identifier; in a more general approach,
  219.            a table would be checked for the corresponding system ID.
  220.            For version-dependent public entities, a real application
  221.            would use different tables, depending on the display device
  222.            (or different suffixes, in a scheme like that used here).
  223.            If this routine is modified so that, under some conditions,
  224.            it cannot generate a fileid, it should return 0 in those cases.
  225.            FILEOPEN should check for the 0 and return an error code to SGML
  226.            at that time.
  227.            Note 2: This routine allows boundary treatment codes for data
  228.            content notation files (f->fpistore==6) even though such files
  229.            are not parsed.  VM strips the code before displaying the file
  230.            identifier (which is analagous to a text processor stripping it
  231.            before passing it to an application).  Alternatively, this
  232.            routine could be modified so that the code is never inserted
  233.            in the first place.
  234.            Note 3: This is the place to check that system identifiers are
  235.            valid for your environment, and that the boundary code (if
  236.            specified) is valid.  SGML does not check such things because
  237.            it knows nothing about the environment.
  238. */
  239. UNCH *xidgen(f)
  240. struct fpi *f;                /* Pointer to fpi control block. */
  241. {
  242.      UNS i, j;                /* Work variables. */
  243.      UNCH *p;                 /* Work pointer. */
  244.  
  245.      *pd = 4;                 /* Starting length of constructed ID. */
  246.      pd[1] = (char)boundsw;   /* Use default boundary treatment. */
  247.      pd[2] = '=';             /* Boundary treatment delimiter. */
  248.      p = pd+3;                /* Pt after boundary treatment delimiter. */
  249.      /* If a complete system ID was specified, use it all.
  250.         If only the boundary treatment was specified (n=), use it
  251.         when constructing the system ID.
  252.         If the boundary treatment was omitted, append the system ID to
  253.         the default boundary treatment code.
  254.      */
  255.      if (f->fpisysl) {
  256.           if (*(p = f->fpisysis+2)=='=') {
  257.                if (*(--p)>'3' || *p<'0') *p = (char)boundsw;
  258.                if (*(p+2)==EOS) {
  259.                     memcpy(pd, f->fpisysis, 3);
  260.                     p = pd+3;
  261.                }
  262.                else return(f->fpisysis);
  263.           }
  264.           else {
  265.                memcpy(pd+3, f->fpisysis+1, f->fpisysl-1);
  266.                *pd = f->fpisysl+2;
  267.                return(pd);
  268.           }
  269.      }
  270.      /* If not, add a suffix to the entity name to produce a system ID. */
  271.      memcpy(p, f->fpinm+1, (i = f->fpinml-2));
  272.      j = (f->fpipubl ? 1 : 0)*(f->fpiversw>0 ? 2 : 1)*6+f->fpistore;
  273.      memcpy(p+i, genext[j], 5);    /* Add extension.*/
  274.      *pd += (char)(i + 4);         /* Add entity name and extension lengths. */
  275.      return(pd);
  276. }
  277. /******************************************************************************/
  278. /* XIDPATH: Prefixes a path to a system identifier (DOS fileid) if
  279.             path searching is wanted.
  280.             The path buffer is used to build the prefixed fileid.
  281. */
  282. UNCH *xidpath(pt)
  283. UNCH *pt;                     /* Ptr to fileid in temporary storage (len+EOS).*/
  284. {
  285.      UNS i;                   /* Work variable. */
  286.  
  287.       /* If path is to be searched, get the full path name and fileid. */
  288.      if (!cdirsw && ((i = filefind(pt+1, path+1))>1) ) {
  289.           *path = *pt += (char)i;  /* Add len of path to fileid len. */
  290.           pt = path;               /* Return offset of path+fileid. */
  291.      }
  292.      return(pt);
  293. }
  294. /******************************************************************************/
  295. /* FILEFIND: This is the routine to locate a file, using SEARCHPATH.
  296.              If the file is found in the current directory, 1 is returned.
  297.              If found in another directory on the environment path list,
  298.              the length of the path name (no EOS) is returned; otherwise 0.
  299. */
  300. /******************************************************************************/
  301. int filefind(filename, buffer)
  302. char *filename;               /* File to be searched for (with EOS). */
  303. char *buffer;                 /* Buffer for found filename (with EOS). */
  304. {
  305.      char *fptr;              /* Pointer to found filename. */
  306.      unsigned fnlen;          /* Length of filename (+EOS). */
  307.  
  308.      _fmode = (int)O_BINARY;       /* Default file I/O is binary mode. */
  309.      if ((fptr = searchpath(filename))==0)
  310.           return (0);              /* Return if no file found. */
  311.      memcpy( buffer , fptr, (fnlen = (unsigned)strlen(fptr)) );
  312.      if (strlen(filename)==fnlen) return (1);     /* In current directory. */
  313.      buffer[fnlen] = '\0';                        /* Somewhere on path. */
  314.      return ((int)(fnlen+1));
  315. }
  316. /******************************************************************************/
  317.